/*
 * @Filename: SJA_Ctrl.v, clock domain crossing & width conversion
 * @Author: ws
 * @Description: 
 * @Date: 2023-03-20 10:49:51
 * @LastEditTime: 2023-03-20 19:35:43
 * @Company: 662
*/

module SJA_Ctrl(

//=========================== clk & rst ===========================//
input   wire            i_can_clk,                      //CAN_TOP clock, 125M
input   wire            i_can_rst_n,                    //i_can_clk, active low reset
input   wire            i_sys_clk,
input   wire            i_sys_rst_n,

//============================== PE 50M==============================//
input   wire    [31:0]  i_addr_32b,
input   wire            i_wren,
input   wire            i_rden,
input   wire    [31:0]  i_din_32b,
output  reg             o_dout_32b_valid,
output  reg     [31:0]  o_dout_32b,

//============================== SOI 125M==============================//
(*mark_debug="true"*)output  reg    [7:0]    o_soi_addr,                     //SJA_1000 address
(*mark_debug="true"*)output  reg             o_soi_wren,                     //SJA_1000 write enable
(*mark_debug="true"*)output  reg             o_soi_rden,                     //SJA_1000 read enable
(*mark_debug="true"*)output  reg    [7:0]    o_soi_din,                      //write data to SJA_1000
(*mark_debug="true"*)input   wire   [7:0]    i_soi_dout,                     //read data from SJA_1000
(*mark_debug="true"*)input   wire            i_soi_dout_valid,               //read data from SJA_1000 enable
(*mark_debug="true"*)input   wire            i_soi_opr_end_flag              //flag of read or write operation is end

);

/*sys_clk(slow)->can_clk(fast), 2 flip-flop*/
reg     [7:0]   soi_addr;
reg             soi_wren;
reg             soi_rden;
reg     [7:0]   soi_din;
always@(posedge i_can_clk or negedge i_can_rst_n)begin
    if(!i_can_rst_n)begin
        soi_addr <= 8'b0;
        soi_wren <= 1'b0;
        soi_rden <= 1'b0;
        soi_din <= 8'b0;

        o_soi_addr <= 8'b0;
        o_soi_wren <= 1'b0;
        o_soi_rden <= 1'b0;
        o_soi_din <= 8'b0;
    end
    else begin
        soi_addr <= i_addr_32b[9:2];
        soi_wren <= i_wren;
        soi_rden <= i_rden;
        soi_din <= i_din_32b[7:0];

        o_soi_addr <= soi_addr;
        o_soi_wren <= soi_wren;
        o_soi_rden <= soi_rden;
        o_soi_din <= soi_din;
    end
end

(*mark_debug="true"*)reg [1:0] state;
localparam  IDLE_AND_WR = 2'b00,
            RD_S = 2'b01,
            WAIT_S = 2'b10;

/*can_clk(fast)->sys_clk(slow), Asynchronous FIFO*/
(*mark_debug="true"*)reg                     rd_pkt_data_en;                 //read enable
(*mark_debug="true"*)wire            [9:0]   rd_pkt_data_q;                  //read data out [i_soi_opr_end_flag,i_soi_dout_valid,i_soi_dout]
(*mark_debug="true"*)wire                    rd_pkt_data_empty;              //empty

always@(posedge i_sys_clk or negedge i_sys_rst_n)begin
    if(!i_sys_rst_n)begin
        rd_pkt_data_en <= 1'b0;
        o_dout_32b_valid <= 1'b0;
        o_dout_32b <= 32'b0;
        state <= IDLE_AND_WR;
    end
    else begin
        case(state)
            IDLE_AND_WR:begin
                if(!rd_pkt_data_empty)begin
                    rd_pkt_data_en <= 1'b1;
                    if(rd_pkt_data_q[8])begin
                        o_dout_32b_valid <= 1'b0;
                        o_dout_32b <= {24'b0,rd_pkt_data_q[7:0]};
                        state <= RD_S;                
                    end
                    else if(rd_pkt_data_q[9])begin
                        o_dout_32b_valid <= 1'b1;
                        o_dout_32b <= 32'b0;
                        state <= WAIT_S;
                    end
                    else begin
                        o_dout_32b_valid <= 1'b0;
                        o_dout_32b <= 32'b0;
                        state <= WAIT_S;
                    end
                end
                else begin
                    rd_pkt_data_en <= 1'b0;
                    o_dout_32b_valid <= 1'b0;
                    o_dout_32b <= 32'b0;
                    state <= IDLE_AND_WR;
                end
            end

            RD_S:begin
                if(rd_pkt_data_q[9])begin
                    o_dout_32b_valid <= 1'b1;
                    if(!rd_pkt_data_empty)begin
                        rd_pkt_data_en <= 1'b1;
                    end
                    else begin
                        rd_pkt_data_en <= 1'b0;
                    end
                    state <= WAIT_S;
                end
                else begin
                    rd_pkt_data_en <= 1'b0;
                end        
            end

            WAIT_S:begin
                o_dout_32b_valid <= 1'b0;
                o_dout_32b <= 32'b0;
                rd_pkt_data_en <= 1'b0;
                state <= IDLE_AND_WR;
            end

            default:begin
                state <= IDLE_AND_WR;
            end
        endcase
    end
end

ASYNCFIFO_32x10 can_sys_fifo(
            .rd_aclr            (!i_sys_rst_n                                       ),
            .wr_aclr            (!i_can_rst_n                                       ),
			.data				({i_soi_opr_end_flag,i_soi_dout_valid,i_soi_dout}   ),
            .rdclk              (i_sys_clk                                          ),
			.rdreq				(rd_pkt_data_en                                     ),
            .wrclk              (i_can_clk                                          ),
			.wrreq				(i_soi_dout_valid | i_soi_opr_end_flag              ),
			.q					(rd_pkt_data_q                                      ),
            .wrfull             (                                                   ),
	        .wralfull           (                                                   ),
	        .wrempty            (                                                   ),
	        .wralempty          (                                                   ),
	        .rdfull             (                                                   ),
	        .rdalfull           (                                                   ),
			.rdempty			(rd_pkt_data_empty                                  ),
			.rdalempty          (							                        ),
			.wrusedw			(                                                   ),
			.rdusedw			(							                        )
);

endmodule

